# -*- coding=utf8 -*-

import numpy

'''
感知器
http://localhost:4000/blog/neural-network-easy-learning.html
'''

class Perceptron:
    def __init__(self,input_num,activator):
        '''
        初始化感知器，设置输入参数的个数，以及激活函数。
        激活函数的类型为double -> double
        :param input_num: 输入参数的个数
        :param activator: 激活函数
        '''
        self.activator = activator
        self.w = [0.0 for i in range(input_num)]
        self.b = 0.0

    def __str__(self):
        return "w\t%s\tb\t%f" % (self.w,self.b)

    def predict(self,input_vec):

        #return self.activator(
        #    reduce(lambda a, b: a + b, map(lambda (x, w): x * w, zip(input_vec, self.w)), 0.0) + self.b)
        return self.activator(numpy.dot(input_vec,self.w) + self.b)

    def train(self, input_vecs, labels, iteration, rate):
        '''
        输入训练数据：一组向量、与每个向量对应的label；以及训练轮数、学习率         
        :param input_vecs: 一组向量
        :param labels: 每个向量对应的label
        :param iteration: 训练轮数
        :param rate: 学习率
        :return: 
        '''
        for i in range(iteration):
            self._one_iteration(input_vecs,labels,rate)

    def _one_iteration(self, input_vecs, labels, rate):
        '''
        一次迭代，把所有的训练数据过一遍
        :param input_vecs: 一组向量
        :param labels: 每个向量对应的label
        :param rate: 学习率
        :return: 
        '''
        for i in range( len(input_vecs) ):
            output = self.predict(input_vecs[i])
            self._update_weights(input_vecs[i],output,labels[i],rate)

    def _update_weights(self, input_vec, output, label, rate):
        '''
        按照感知器规则更新权重
        :param input_vec: 
        :param output: 
        :param label: 
        :param rate: 
        :return: 
        '''
        delta = label - output;
        self.b += rate * delta;
        # 把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,...]打包在一起
        # 变成[(x1,w1),(x2,w2),(x3,w3),...]
        # 然后利用感知器规则更新权重
        self.w = map( lambda (x,w) : w + rate * delta * x , zip( input_vec,self.w ) )